/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.project.controller;

import edu.project.annotations.ColumnAnnotation;
import edu.project.annotations.InsertableAnnotation;
import edu.project.model.Student;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Hashtable;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author phichidev
 */


/* Cái Class CodeGenerator này dùng để Sinh ra hẳn 1 file DatabaseHelper: file này có chức năng insert, update, delete cho
 * các đối tượng Student, Teacherr, Staff...
 *
 * Đại khái như là. Anh thấy trong Class CodeGenerator này có hàm insert đấy, khi mình chạy hàm insert trong CodeGenerator
 * và truyền cho nó cái Input là Object gì thì nó ra hàm insertObject. Ví dụ mình truyền vào là student thì sau khi mình ghi ra
 * file DatabaseHelper thì trong file này có hàm ínertStudent y xì như thế này :
 *
 *      public void insertStudent(Student student) {

        PreparedStatement ps = connection.prepareStatement("INSERT INTO Student(student_name,student_age)  VALUES (?,?)");
        ps.setString(1, student.getName());
        ps.setInt(2, student.getAge());
    }
 *
 * tương tự khi mình truyền input là đối tượng Teacher hay Staff thì nó sẽ Generate ra các method là insertTeacher, insertStaff
 *
 * Cứ thế mình sẽ xây dựng tiếp hàm generateUpdate, generateDelete...rồi mình ghi ra file DatabaseHelper.
 *
 * Đối tượng CodeWWriter sẽ đc giải thích ở Class đó
 *
 */
public class CodeGenerator<T> {

    public static Hashtable<String, String> mapMethods = new Hashtable<String, String>();

    static {
        mapMethods.put("String", "setString");
        mapMethods.put("int", "setInt");
    }

    public CodeWriter generateInsert(Object object) {
        //Khởi tạo CodeWriter để lưu các kí tự để xuất ra file DatabaseHelper
        CodeWriter cw = new CodeWriter();
        Class c = object.getClass();
        String sName = c.getSimpleName();
        //Reflection && Annotations
        cw.beginMethod("public void insert" + sName + "(" + getVariable(c) + ")");
        cw.append("PreparedStatement ps = connection.prepareStatement(\"INSERT INTO " + sName + "(");
        int countField = 0;

        //Vòn for này để quét hết các field của Object đc input vào
        for (Field field : c.getFields()) {
            ColumnAnnotation columnAnnotation = field.getAnnotation(ColumnAnnotation.class); //Tìm đến các field nhờ mình Annotation
            //If để mình kiểm tra xem cái field đó có đc insert hay koo. Ví dụ trong Student có field id thì mình koo đc insert nó vì ID mình để kiểu Identify, nó tự tăng rồi
            if (columnAnnotation != null && field.getAnnotation(InsertableAnnotation.class) != null) {
                countField++;
                cw.append(columnAnnotation.name() + ",");
            }
        }
        cw.backSpace(); // Xóa cái dấu , đi. Vì mình insert thừa trong vognf lặp for
        cw.append(") ");
        cw.append(" VALUES (");
        for (int i = 0; i < countField; i++) {
            cw.append("?,");
        }
        cw.backSpace();
        cw.append(")\");");

        cw.writeLine();

        int indexField = 0; // Biến này để xem cái field này nằm ở vị trí thứ mấy (ví dụ đẻ khi mình setString(1, "dsad") chẳng hạn thì mình biết đc nó nằm ở field thứ mấy để set)
        for (Field field : c.getFields()) {
            String type = mapMethods.get(field.getType().getSimpleName());
            if (type != null) {

                InsertableAnnotation insertableAnnotation = field.getAnnotation(InsertableAnnotation.class);
                if (insertableAnnotation != null && insertableAnnotation.insert()) {
                    indexField++;
                    cw.append("ps.");
                    cw.writeLine(type + "(" + indexField + "," + getMethod(c, field) + ");");
                    //System.out.println(setMethod(c, field, "Interger.parseString(row...)"));
                }
            }
        }
        cw.endMethod();
        System.out.println(cw.toString());
        return cw;
    }

    //Hàm này sẽ bị xóa vì nó chỉ làm mẫu để tí mình làm cái hàm generateGet
    public Student getStudent(ResultSet resultSet) throws Exception {

        Student student = new Student();


        student.setName(resultSet.getString(1));
        student.setAge(resultSet.getInt(2));
        //...


        return student;
    }

    //Hàm này trả về String thể hiện tham số đầu vào. Ví dụ như (Student student)
    public String getVariable(Class c) {
        return c.getSimpleName() + " " + c.getSimpleName().toLowerCase();
    }

    //Hàm này trả về kiểu String. Ví dụ như là student.getName()
    public String getMethod(Class c, Field field) {
        return c.getSimpleName().toLowerCase() + ".get" + toUpperFirst(field.getName()) + "()";
    }


    //Cái hàm này để tí nữa mình làm generateUpdate.
    public String setMethod(Class c, Field field, String content) {
        return c.getSimpleName().toLowerCase() + "." + "set" + toUpperFirst(field.getName()) + "(" + content + ");";
        //setString()
    }

    //Hàm này sẽ trả về String viết hoa chũ cái đầu tiên. Ví dụ. st = age chẳng hạn. thfi nó sẽ là Age
    public String toUpperFirst(String st) {
        return st.substring(0, 1).toUpperCase() + st.substring(1);
    }

    public static void main(String[] args) {
        new CodeGenerator().generateInsert(new Student());
    }
}


